
Public Class ACDataGridView

#Region "Eventos"
   Public Event ACHelpTextBoxButtonClick(ByVal sender As Object, ByVal e As DataGridViewButtonClickArgs)
   Public Event ACHelpTextBoxChanged(ByVal sender As Object, ByVal e As System.EventArgs)
   Public Event ACComboBoxSelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs)
   Public Event ACDateTimePickerValueChanged(ByVal sender As Object, ByVal e As System.EventArgs)
   Public Event ACTextBoxTextChanged(ByVal sender As Object, ByVal e As System.EventArgs)
   Public Event ACCellInEditModeKeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs)
   Public Event ACNumericUpDownValueChanged(ByVal sender As Object, ByVal e As System.EventArgs)
#End Region

#Region "Constructor"
   Public Sub New()

      ' This call is required by the Windows Form Designer.
      InitializeComponent()

      ' Add any initialization after the InitializeComponent() call.
      MyBase.AutoGenerateColumns = False
      MyBase.VirtualMode = True
   End Sub

#End Region

   Public Property ACComboBoxSelectedIndex(ByVal row As Integer, ByVal column As Integer) As Integer
      Get
         Dim OldCell As DataGridViewCell = Me.CurrentCell
         Dim Cell As DataGridViewCell = Me.Rows(row).Cells(column)
         Dim SelectedIndex As Integer
         Dim cbo As ComboBox
         Me.CurrentCell = Cell
         Me.BeginEdit(True)
         cbo = CType(Me.EditingControl(), ComboBox)
         SelectedIndex = cbo.SelectedIndex
         Me.CurrentCell = OldCell
         Return SelectedIndex
      End Get
      Set(ByVal value As Integer)
         Dim OldCell As DataGridViewCell = Me.CurrentCell
         Dim Cell As DataGridViewCell = Me.Rows(row).Cells(column)
         Dim cbo As New ComboBox
         Me.CurrentCell = Cell
         Me.BeginEdit(True)
         cbo = CType(Me.EditingControl(), ComboBox)
         cbo.SelectedIndex = value
         Me.CurrentCell = OldCell
      End Set
   End Property

   Public Property ACHelpTextBoxText() As String
      Get
         Dim txt As ACHelpTextBox
         txt = CType(Me.EditingControl(), TextBox)
         If txt Is Nothing Then
            Return ""
         Else
            Return txt.Text
         End If
      End Get
      Set(ByVal value As String)
         Dim txt As ACHelpTextBox
         txt = CType(Me.EditingControl(), TextBox)
         If Not txt Is Nothing Then
            txt.Text = value
         End If
      End Set
   End Property

   Public Property ACTextBoxText() As String
      Get
         Dim txt As TextBox
         txt = CType(Me.EditingControl(), TextBox)
         If txt Is Nothing Then
            Return ""
         Else
            Return txt.Text
         End If
      End Get
      Set(ByVal value As String)
         Dim txt As TextBox
         txt = CType(Me.EditingControl(), TextBox)
         If Not txt Is Nothing Then
            txt.Text = value
         End If
      End Set
   End Property

   Public Property ACHelpTextBoxTag() As String
      Get
         Dim txt As ACHelpTextBox
         txt = Me.EditingControl()
         If txt Is Nothing Then
            Return ""
         Else
            Return txt.Tag
         End If
      End Get
      Set(ByVal value As String)
         Dim txt As ACHelpTextBox
         txt = Me.EditingControl()
         If Not txt Is Nothing Then
            txt.Tag = value
            Me.CurrentCell.Tag = value
         End If
      End Set
   End Property

   Public Property ACNumericUpDownValue() As Decimal
      Get
         Dim nud As ACDataGridViewNumericUpDown
         nud = CType(Me.EditingControl(), NumericUpDown)
         If nud Is Nothing Then
            Return 0
         Else
            Return nud.Value
         End If
      End Get
      Set(ByVal value As Decimal)
         Dim nud As ACDataGridViewNumericUpDown
         nud = CType(Me.EditingControl(), NumericUpDown)
         If Not nud Is Nothing Then
            nud.Value = value
         End If
      End Set
   End Property

   Public Shadows Property DataSource() As Object
      Get
         Return MyBase.DataSource
      End Get
      Set(ByVal value As Object)
         MyBase.DataSource = value
      End Set
   End Property

#Region "Columnas"

   Private Function AddColumn(ByVal dc As DataGridViewTextBoxColumn) As Integer
      Return MyBase.Columns.Add(dc)
   End Function

   Private Function AddColumn(ByVal dc As DataGridViewComboBoxColumn) As Integer
      Return MyBase.Columns.Add(dc)
   End Function

   Private Function AddColumn(ByVal dc As DataGridViewCheckBoxColumn) As Integer
      Return MyBase.Columns.Add(dc)
   End Function

   Private Function AddColumn(ByVal dc As DataGridViewLinkColumn) As Integer
      Return MyBase.Columns.Add(dc)
   End Function

   Private Function AddColumn(ByVal dc As DataGridViewButtonColumn) As Integer
      Return MyBase.Columns.Add(dc)
   End Function

   Private Function AddColumn(ByVal dc As ACDataGridViewDateTimePickerColumn) As Integer
      Return MyBase.Columns.Add(dc)
   End Function

   Private Function AddColumn(ByVal dc As ACDataGridViewNumericUpDownColumn) As Integer
      Return MyBase.Columns.Add(dc)
   End Function

   Private Function AddColumn(ByVal dc As ACDataGridViewHelpTextBoxColumn) As Integer
      Return MyBase.Columns.Add(dc)
   End Function

   Public Sub ACAddDateTimePicker(ByVal HeaderText As String, ByVal DataColumnName As String, ByVal Width As Integer, ByVal [ReadOnly] As Boolean, Optional ByVal ColumnName As String = "")
      Dim col As New ACDataGridViewDateTimePickerColumn
      If Not ColumnName.Trim = "" Then col.Name = ColumnName
      col.HeaderText = HeaderText
      col.DataPropertyName = DataColumnName
      col.Width = Width
      col.ReadOnly = [ReadOnly]
      Me.AddColumn(col)
   End Sub

   Public Sub ACAddNumericUpDown(ByVal HeaderText As String, ByVal DataColumnName As String, ByVal Width As Integer, ByVal [ReadOnly] As Boolean, Optional ByVal ColumnName As String = "")
      Dim col As New ACDataGridViewNumericUpDownColumn
      If Not ColumnName.Trim = "" Then col.Name = ColumnName
      col.HeaderText = HeaderText
      col.DataPropertyName = DataColumnName
      col.Width = Width
      col.ReadOnly = [ReadOnly]
      Me.AddColumn(col)
   End Sub

   Public Sub ACAddTextBoxColumn(ByVal HeaderText As String, ByVal DataColumnName As String, ByVal Width As Integer, ByVal [ReadOnly] As Boolean, Optional ByVal ColumnName As String = "")
      Dim col As New DataGridViewTextBoxColumn
      If Not ColumnName.Trim = "" Then col.Name = ColumnName
      col.HeaderText = HeaderText
      col.DataPropertyName = DataColumnName
      col.Width = Width
      col.ReadOnly = [ReadOnly]
      Me.AddColumn(col)
   End Sub

   Public Sub ACAddHelpTextBoxColumn(ByVal HeaderText As String, ByVal DataColumnName As String, ByVal Width As Integer, ByVal [ReadOnly] As Boolean, Optional ByVal ColumnName As String = "")
      Dim col As New ACDataGridViewHelpTextBoxColumn
      If Not ColumnName.Trim = "" Then col.Name = ColumnName
      col.HeaderText = HeaderText
      col.DataPropertyName = DataColumnName
      col.Width = Width
      col.ReadOnly = [ReadOnly]
      Me.AddColumn(col)
   End Sub

   Public Sub ACAddComboBoxColumn(ByVal HeaderText As String, ByVal DataColumnName As String, ByVal Width As Integer, ByVal [ReadOnly] As Boolean, ByVal dt As Object, ByVal DisplayMember As String, ByVal ValueMember As String, Optional ByVal ColumnName As String = "")
      Dim col As New DataGridViewComboBoxColumn
      If Not ColumnName.Trim = "" Then col.Name = ColumnName
      col.Width = Width
      col.ReadOnly = [ReadOnly]
      col.HeaderText = HeaderText
      col.DataPropertyName = DataColumnName
      col.DataSource = dt
      col.ValueMember = ValueMember
      col.DisplayMember = DisplayMember
      col.FlatStyle = FlatStyle.Flat
      col.DisplayStyleForCurrentCellOnly = True
      Me.AddColumn(col)
   End Sub

   Public Sub ACAddCheckBoxColumn(ByVal HeaderText As String, ByVal DataColumnName As String, ByVal Width As Integer, ByVal [ReadOnly] As Boolean, Optional ByVal ColumnName As String = "")
      Dim col As New DataGridViewCheckBoxColumn
      If Not ColumnName.Trim = "" Then col.Name = ColumnName
      col.HeaderText = HeaderText
      col.DataPropertyName = DataColumnName
      col.Width = Width
      col.ReadOnly = [ReadOnly]
      Me.AddColumn(col)
   End Sub

   Public Sub ACAddLinkColumn(ByVal HeaderText As String, ByVal DataColumnName As String, ByVal Width As Integer, ByVal [ReadOnly] As Boolean, Optional ByVal ColumnName As String = "")
      Dim col As New DataGridViewLinkColumn
      If Not ColumnName.Trim = "" Then col.Name = ColumnName
      col.HeaderText = HeaderText
      col.DataPropertyName = DataColumnName
      col.Width = Width
      col.ReadOnly = [ReadOnly]
      Me.AddColumn(col)
   End Sub

   Public Sub ACAddButtonColumn(ByVal HeaderText As String, ByVal DataColumnName As String, ByVal Width As Integer, ByVal [ReadOnly] As Boolean, Optional ByVal ColumnName As String = "")
      Dim col As New DataGridViewButtonColumn
      If Not ColumnName.Trim = "" Then col.Name = ColumnName
      col.HeaderText = HeaderText
      col.DataPropertyName = DataColumnName
      Me.AddColumn(col)
   End Sub

#End Region

#Region "Manejo de Eventos"

   Public Sub OnEventHelpTextBoxButtonClick(ByVal sender As Object, ByVal e As System.EventArgs)
      RaiseEvent ACHelpTextBoxButtonClick(Me.CurrentCell, New DataGridViewButtonClickArgs(Me.CurrentCell.RowIndex, Me.CurrentCell.ColumnIndex))
   End Sub

   Public Sub OnEventHelpTextBoxChanged(ByVal sender As Object, ByVal e As System.EventArgs)
      RaiseEvent ACHelpTextBoxChanged(sender, e)
   End Sub

   Public Sub OnEventComboBoxSelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs)
      RaiseEvent ACComboBoxSelectedIndexChanged(sender, e)
   End Sub

   Public Sub OnEventDateTimePickerValueChanged(ByVal sender As Object, ByVal e As System.EventArgs)
      RaiseEvent ACDateTimePickerValueChanged(sender, e)
   End Sub

   Public Sub OnEventTextBoxTextChanged(ByVal sender As Object, ByVal e As System.EventArgs)
      RaiseEvent ACTextBoxTextChanged(sender, e)
   End Sub

   Public Sub OnEventNumericUpDownValueChanged(ByVal sender As Object, ByVal e As System.EventArgs)
      RaiseEvent ACNumericUpDownValueChanged(sender, e)
   End Sub

   Public Sub OnEventComboBoxLeave(ByVal sender As Object, ByVal e As System.EventArgs)
      Dim cbo As ComboBox = CType(sender, ComboBox)
      If cbo IsNot Nothing Then RemoveHandler cbo.SelectedIndexChanged, AddressOf Me.OnEventComboBoxSelectedIndexChanged
   End Sub

   Public Sub OnEventDateTimePickerLeave(ByVal sender As Object, ByVal e As System.EventArgs)
      Dim dtp As DateTimePicker = CType(sender, DateTimePicker)
      If dtp IsNot Nothing Then RemoveHandler dtp.ValueChanged, AddressOf Me.OnEventDateTimePickerValueChanged
   End Sub

   Public Sub OnEventTextBoxLeave(ByVal sender As Object, ByVal e As System.EventArgs)
      Dim txt As TextBox = CType(sender, TextBox)
      If txt IsNot Nothing Then RemoveHandler txt.TextChanged, AddressOf Me.OnEventTextBoxTextChanged
   End Sub

   Public Sub OnEventNumericUpDownLeave(ByVal sender As Object, ByVal e As System.EventArgs)
      Dim nud As NumericUpDown = CType(sender, NumericUpDown)
      If nud IsNot Nothing Then RemoveHandler nud.ValueChanged, AddressOf Me.OnEventNumericUpDownValueChanged
   End Sub

   Private Sub ACDataGridView_DataError(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewDataErrorEventArgs) Handles Me.DataError
      'Aqui manejar algunos errores
      'MessageBox.Show(e.Exception.Message)
      'Select Case e.Context
      '    Case DataGridViewDataErrorContexts.Commit

      '    Case Else

      'End Select
   End Sub

   Private Sub ACDataGridView_EditingControlShowing(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewEditingControlShowingEventArgs) Handles Me.EditingControlShowing
      Select Case e.Control.GetType.Name
         Case "ACDataGridViewHelpTextBox"
            Dim txt As ACDataGridViewHelpTextBox
            txt = CType(e.Control, ACDataGridViewHelpTextBox)
            If txt IsNot Nothing Then
               txt.Tag = Me.CurrentCell.Tag
               RemoveHandler txt.ButtonClick, AddressOf Me.OnEventHelpTextBoxButtonClick
               AddHandler txt.ButtonClick, AddressOf Me.OnEventHelpTextBoxButtonClick
               RemoveHandler txt.TextChanged, AddressOf Me.OnEventHelpTextBoxChanged
               AddHandler txt.TextChanged, AddressOf Me.OnEventHelpTextBoxChanged
            End If
         Case "DataGridViewComboBoxEditingControl", "ComboBox"
            Dim cbo As ComboBox
            cbo = CType(e.Control, ComboBox)
            If cbo IsNot Nothing Then
               RemoveHandler cbo.SelectedIndexChanged, AddressOf Me.OnEventComboBoxSelectedIndexChanged
               AddHandler cbo.SelectedIndexChanged, AddressOf Me.OnEventComboBoxSelectedIndexChanged

               RemoveHandler cbo.Leave, AddressOf Me.OnEventComboBoxLeave
               AddHandler cbo.Leave, AddressOf Me.OnEventComboBoxLeave
            End If
         Case "ACDataGridViewDateTimePicker"
            Dim dtp As DateTimePicker
            dtp = CType(e.Control, DateTimePicker)
            If dtp IsNot Nothing Then
               RemoveHandler dtp.ValueChanged, AddressOf OnEventDateTimePickerValueChanged
               AddHandler dtp.ValueChanged, AddressOf OnEventDateTimePickerValueChanged

               RemoveHandler dtp.Leave, AddressOf Me.OnEventDateTimePickerLeave
               AddHandler dtp.Leave, AddressOf Me.OnEventDateTimePickerLeave
            End If
         Case "ACGridViewTextBoxEditingControl"
            Dim txt As TextBox
            txt = CType(e.Control, TextBox)
            If txt IsNot Nothing Then
               RemoveHandler txt.TextChanged, AddressOf OnEventHelpTextBoxChanged
               AddHandler txt.TextChanged, AddressOf OnEventHelpTextBoxChanged

               RemoveHandler txt.Leave, AddressOf Me.OnEventTextBoxLeave
               AddHandler txt.Leave, AddressOf Me.OnEventTextBoxLeave
            End If
         Case "ACDataGridViewNumericUpDown"
            Dim nud As NumericUpDown
            nud = CType(e.Control, NumericUpDown)
            If nud IsNot Nothing Then
               RemoveHandler nud.ValueChanged, AddressOf OnEventNumericUpDownValueChanged
               AddHandler nud.ValueChanged, AddressOf OnEventNumericUpDownValueChanged

               RemoveHandler nud.Leave, AddressOf Me.OnEventNumericUpDownLeave
               AddHandler nud.Leave, AddressOf Me.OnEventNumericUpDownLeave
            End If
      End Select
   End Sub

   Protected Overrides Function ProcessDialogKey(ByVal keyData As System.Windows.Forms.Keys) As Boolean
      If Not CurrentCell Is Nothing Then
         If Me.CurrentCell.IsInEditMode Then
            RaiseEvent ACCellInEditModeKeyPress(Me, New KeyEventArgs(keyData))
         Else
            Return MyBase.ProcessDialogKey(keyData)
         End If
      End If
   End Function

#End Region

   Public Sub MakeMasterDetailBinding(ByVal MasterBindingSource As BindingSource, ByVal RelationName As String)
      Dim bsDetalle As New BindingSource
      bsDetalle.DataSource = MasterBindingSource
      bsDetalle.DataMember = RelationName
      Me.DataSource = bsDetalle
   End Sub

End Class


Public Class DataGridViewButtonClickArgs
    Inherits EventArgs
    Dim mRow, mCol As Integer

    Public Sub New(ByVal pRow As Integer, ByVal pCol As Integer)
        mRow = pRow
        mCol = pCol
    End Sub

    Public ReadOnly Property Row() As Integer
        Get
            Return mRow
        End Get
    End Property

    Public ReadOnly Property Column() As Integer
        Get
            Return mCol
        End Get
    End Property
End Class